package br.com.mtg.movethegarbage.graphics;

//Android BFF Loader/Renderer v1.07
//Copyright 2011 Karl Walsh
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import br.com.mtg.movethegarbage.framework.Game;

public class TexFont
{
	Game game;
	float xScale, yScale;
	int fntTexWidth, fntTexHeight;
	int fntCellWidth, fntCellHeight;
	int BPP, firstCharOffset, colCount;
	int[] charWidth;
	int texID;
	float redVal, greenVal, blueVal;
	int curX, curY;
	int UVarray[];
	GL10 gl;

	public TexFont(Game _game)
	{
		game = _game;

		redVal = greenVal = blueVal = 1.0f;
		curX = curY = 0;

		xScale = yScale = 1.0f;

		charWidth = new int[256];

		UVarray = new int[4];

		gl = game.getGraphics().getGL();
	}

	public boolean loadFontAlt() throws Exception
	{
		byte[] head = new byte[20];

		gl = game.getGraphics().getGL();

		int temp[] = new int[1];
		gl.glGenTextures(1, temp, 0);
		texID = temp[0];

		gl.glBindTexture(GL10.GL_TEXTURE_2D, texID);

		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

		try
		{
			ArrayList<String> files = new ArrayList<String>();
			files.add("data0.bin");
			files.add("data1.bin");
			ByteBuffer buffer = game.getFileIO().mergeParts(files);

			buffer.get(head, 0, 20);

			if (buffer.array().length < 20)
			{
				throw new IOException("Header read failed");
			}

			ByteBuffer headBuf = ByteBuffer.wrap(head);

			int h0 = getUnsignedByteVal(headBuf.get());
			int h1 = getUnsignedByteVal(headBuf.get());

			if (h0 != 0xBF || h1 != 0xF2)
			{
				throw new IOException("Bad header signature");
			}

			fntTexWidth = flipEndian(headBuf.getInt());
			fntTexHeight = flipEndian(headBuf.getInt());

			fntCellWidth = flipEndian(headBuf.getInt());
			fntCellHeight = flipEndian(headBuf.getInt());

			if (fntCellWidth <= 0 || fntCellHeight <= 0)
			{
				throw new IOException("Invalid header content");
			}

			colCount = fntTexWidth / fntCellWidth;

			BPP = getUnsignedByteVal(headBuf.get());

			firstCharOffset = getUnsignedByteVal(headBuf.get());

			for (int wLoop = 0; wLoop < 256; ++wLoop)
			{
				charWidth[wLoop] = buffer.get();
			}

			int bitLen = (fntTexHeight * fntTexWidth) * (BPP / 8);
			byte bits[] = new byte[bitLen];

			buffer.get(bits, 0, bitLen);

			ByteBuffer pix = ByteBuffer.allocate(bits.length);
			int lineLen = fntTexWidth * (BPP / 8);

			for (int lines = fntTexHeight - 1; lines > 0; --lines)
			{
				pix.put(bits, lines * lineLen, lineLen);
			}

			gl.glBindTexture(GL10.GL_TEXTURE_2D, texID);

			switch (BPP)
			{
				case 8:
					gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_ALPHA, fntTexWidth, fntTexHeight, 0, GL10.GL_ALPHA, GL10.GL_UNSIGNED_BYTE, pix);
					break;

				case 24:
					gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, fntTexWidth, fntTexHeight, 0, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, pix);
					break;

				case 32:
					gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, fntTexWidth, fntTexHeight, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pix);
					break;
			}

		}
		catch (java.io.EOFException e)
		{
			throw e;
		}
		catch (java.io.IOException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw e;
		}

		return true;
	}

	public boolean loadFont(String fontName) throws Exception
	{
		InputStream uStream = game.getFileIO().readAsset(fontName);
		DataInputStream in = new DataInputStream(uStream);

		gl = game.getGraphics().getGL();

		int temp[] = new int[1];
		gl.glGenTextures(1, temp, 0);
		texID = temp[0];

		gl.glBindTexture(GL10.GL_TEXTURE_2D, texID);

		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

		int h0 = in.readUnsignedByte();
		int h1 = in.readUnsignedByte();

		if (h0 != 0xBF || h1 != 0xF2)
		{
			in.close();
			return false;
		}

		fntTexWidth = flipEndian(in.readInt());
		fntTexHeight = flipEndian(in.readInt());

		fntCellWidth = flipEndian(in.readInt());
		fntCellHeight = flipEndian(in.readInt());

		if (fntCellWidth <= 0 || fntCellHeight <= 0)
		{
			throw new IOException("Invalid header content");
		}

		colCount = fntTexWidth / fntCellWidth;

		BPP = in.readUnsignedByte();

		firstCharOffset = in.readUnsignedByte();

		for (int wLoop = 0; wLoop < 256; ++wLoop)
		{
			charWidth[wLoop] = in.readUnsignedByte();
		}

		int bitLen = (fntTexHeight * fntTexWidth) * (BPP / 8);
		byte bits[] = new byte[bitLen];

		in.read(bits, 0, bitLen);

		in.close();

		ByteBuffer pix = ByteBuffer.allocate(bits.length);
		int lineLen = fntTexWidth * (BPP / 8);

		for (int lines = fntTexHeight - 1; lines > 0; --lines)
		{
			pix.put(bits, lines * lineLen, lineLen);
		}

		gl.glBindTexture(GL10.GL_TEXTURE_2D, texID);

		switch (BPP)
		{
			case 8:
				gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_ALPHA, fntTexWidth, fntTexHeight, 0, GL10.GL_ALPHA, GL10.GL_UNSIGNED_BYTE, pix);
				break;

			case 24:
				gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGB, fntTexWidth, fntTexHeight, 0, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, pix);
				break;

			case 32:
				gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, fntTexWidth, fntTexHeight, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pix);
				break;
		}

		return true;
	}

	int flipEndian(int val)
	{
		return (val >>> 24) | (val << 24) | ((val << 8) & 0x00FF0000) | ((val >> 8) & 0x0000FF00);
	}

	int getUnsignedByteVal(byte val)
	{
		if (val < 0)
			return 256 + val;
		else
			return val;
	}

	public void setScale(float scaleVal)
	{
		xScale = yScale = scaleVal;
	}

	public void setScale(float xScaleVal, float yScaleVal)
	{
		xScale = xScaleVal;
		yScale = yScaleVal;
	}

	public void setPolyColor(float red, float green, float blue)
	{
		redVal = red;
		greenVal = green;
		blueVal = blue;
	}

	public void setCursor(int x, int y)
	{
		curX = x;
		curY = y;
	}

	public void print(String text)
	{
		float xPos = curX;

		float cellWidth = fntCellWidth * xScale;
		float cellHeight = fntCellHeight * yScale;

		gl = game.getGraphics().getGL();

		UVarray[2] = fntCellWidth;
		UVarray[3] = fntCellHeight;

		gl.glColor4f(redVal, greenVal, blueVal, 1.0f);
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, texID);

		for (int index = 0; index != text.length(); ++index)
		{
			int glyph = text.charAt(index) - firstCharOffset;
			int col = glyph % colCount;
			int row = (glyph / colCount) + 1;

			UVarray[0] = col * fntCellWidth;
			UVarray[1] = fntTexHeight - (row * fntCellHeight);

			((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, UVarray, 0);
			((GL11Ext) gl).glDrawTexfOES(xPos, curY, 0.0f, cellWidth, cellHeight);

			xPos += (xScale * charWidth[glyph + firstCharOffset]);
		}

		curX = (int) xPos;
	}

	public void printAt(String text, float x, float y)
	{
		int glyph, col, row;
		float xPos = x;

		float cellWidth = fntCellWidth * xScale;
		float cellHeight = fntCellHeight * yScale;

		UVarray[2] = fntCellWidth;
		UVarray[3] = fntCellHeight;

		gl = game.getGraphics().getGL();

		gl.glColor4f(redVal, greenVal, blueVal, 1.0f);
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, texID);

		for (int index = 0; index != text.length(); ++index)
		{
			glyph = text.charAt(index) - firstCharOffset;
			col = glyph % colCount;
			row = (glyph / colCount) + 1;

			UVarray[0] = col * fntCellWidth;
			UVarray[1] = fntTexHeight - (row * fntCellHeight);

			((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, UVarray, 0);
			((GL11Ext) gl).glDrawTexfOES(xPos, y, 0.0f, cellWidth, cellHeight);

			xPos += (xScale * charWidth[glyph + firstCharOffset]);
		}

		curX = (int) xPos;
	}

	public int getTextLength(String text)
	{
		float len = 0.0f;

		for (int index = 0; index != text.length(); ++index)
		{
			len += (xScale * charWidth[text.charAt(index)]);
		}

		return (int) len;
	}

	public int getTextHeight()
	{
		return (int) (fntCellHeight * yScale);
	}

}
